Change semantics of the draw signal
authorBenjamin Otte <otte@redhat.com>
Tue, 14 Sep 2010 14:42:16 +0000 (16:42 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 26 Sep 2010 13:11:42 +0000 (15:11 +0200)
Previously, we tried to move the context's origin to the widget's top
left location, no matter what window the paint was happening on. Now we
only do that for child windows of the widget's window and leave the
context untouched for windows that the widget has created outside its
own hierarchy. In those casses, we also don't clip the context to
the widget's allocation.

Includes fixes to GtkHandlebox for this effect and fixes all known
issues with it.

These semantics assume that gtk_widget_draw() should only draw the parts
of a widget that are inside child windows and not draw stuff that is
located in completely different GdkWindows. In the handlebox case, it
means that it should only draw the handle when it is attached, but not
when it isn't. We'll likely need a special draw function for the
detached handlebox if we want to draw it.

gtk/gtkhandlebox.c
gtk/gtkwidget.c
gtk/gtkwidget.h

index 0cef90f51bc53a091ab80208f63f029380785020..4253fb50e316fb341945a919397cf2d86d43fd54 100644 (file)
@@ -927,20 +927,13 @@ gtk_handle_box_paint (GtkWidget      *widget,
   GtkHandleBoxPrivate *priv = hb->priv;
   GtkBin *bin = GTK_BIN (widget);
   GtkWidget *child;
-  gint x, y, width, height;
+  gint width, height;
   GdkRectangle rect;
   gint handle_position;
   GtkOrientation handle_orientation;
 
   handle_position = effective_handle_position (hb);
 
-  cairo_save (cr);
-
-  gdk_window_get_origin (gtk_widget_get_window (widget), &x, &y);
-  cairo_translate (cr, -x, -y);
-  gdk_window_get_origin (priv->bin_window, &x, &y);
-  cairo_translate (cr, x, y);
-
   gdk_drawable_get_size (priv->bin_window, &width, &height);
 
   gtk_cairo_paint_box (gtk_widget_get_style (widget),
@@ -991,8 +984,6 @@ gtk_handle_box_paint (GtkWidget      *widget,
                     rect.x, rect.y, rect.width, rect.height, 
                     handle_orientation);
 
-  cairo_restore (cr);
-
   child = gtk_bin_get_child (bin);
   if (child != NULL && gtk_widget_get_visible (child))
     GTK_WIDGET_CLASS (gtk_handle_box_parent_class)->draw (widget, cr);
@@ -1010,8 +1001,7 @@ gtk_handle_box_draw (GtkWidget *widget,
       if (priv->child_detached)
         gtk_handle_box_draw_ghost (hb, cr);
     }
-
-  if (gtk_cairo_should_draw_window (cr, priv->bin_window))
+  else if (gtk_cairo_should_draw_window (cr, priv->bin_window))
     gtk_handle_box_paint (widget, cr);
   
   return FALSE;
index 3a41b72fe8fc90265b52e698f9122ec4404b17b2..8b77e21e52127c301bfd5f17013bddf97b8ad4a0 100644 (file)
@@ -5124,16 +5124,20 @@ gtk_cairo_should_draw_window (cairo_t *cr,
  */
 void
 _gtk_widget_draw_internal (GtkWidget *widget,
-                           cairo_t   *cr)
+                           cairo_t   *cr,
+                           gboolean   clip_to_size)
 {
   if (!gtk_widget_is_drawable (widget))
     return;
 
-  cairo_rectangle (cr, 
-                   0, 0,
-                   widget->priv->allocation.width,
-                   widget->priv->allocation.height);
-  cairo_clip (cr);
+  if (clip_to_size)
+    {
+      cairo_rectangle (cr, 
+                       0, 0,
+                       widget->priv->allocation.width,
+                       widget->priv->allocation.height);
+      cairo_clip (cr);
+    }
 
   if (gdk_cairo_get_clip_rectangle (cr, NULL))
     {
@@ -5149,9 +5153,10 @@ static gboolean
 gtk_widget_real_expose_event (GtkWidget      *widget,
                              GdkEventExpose *expose)
 {
-  GdkWindow *window;
+  GdkWindow *window, *w;
   gboolean result = FALSE;
   cairo_t *cr;
+  int x, y;
 
   if (!gtk_widget_is_drawable (widget))
     return FALSE;
@@ -5162,37 +5167,32 @@ gtk_widget_real_expose_event (GtkWidget      *widget,
   gdk_cairo_region (cr, expose->region);
   cairo_clip (cr);
 
-  /* translate cairo context properly */
-  window = gtk_widget_get_window (widget);
-  if (window != expose->window)
+  if (!gtk_widget_get_has_window (widget))
     {
-      int x, y;
-
-      if (gdk_window_get_parent (expose->window) == window)
-        {
-          gdk_window_get_position (expose->window, &x, &y);
-        }
-      else
-        {
-          int ex, ey;
-          gdk_window_get_origin (expose->window, &ex, &ey);
-          gdk_window_get_origin (window, &x, &y);
-          x = ex - x;
-          y = ey - y;
-        }
-
-      cairo_translate (cr, -x, -y);
+      x = widget->priv->allocation.x;
+      y = widget->priv->allocation.y;
+    }
+  else
+    {
+      x = 0;
+      y = 0;
     }
 
+  /* translate cairo context properly */
+  window = gtk_widget_get_window (widget);
 
-  if (!gtk_widget_get_has_window (widget))
+  for (w = expose->window; w && w != window; w = gdk_window_get_parent (w))
     {
-      cairo_translate (cr,
-                       widget->priv->allocation.x,
-                       widget->priv->allocation.y);
+      int wx, wy;
+      gdk_window_get_position (w, &wx, &wy);
+      x -= wx;
+      y -= wy;
     }
 
-  _gtk_widget_draw_internal (widget, cr);
+  if (w)
+    cairo_translate (cr, x, y);
+
+  _gtk_widget_draw_internal (widget, cr, w != NULL);
 
   /* unset here, so if someone keeps a reference to cr we
    * don't leak the window. */
index 3ab1bd43e8b4b450ad8def0c19a70cd914bbccda..1e4d61ba3072f141a61e6d900a50f6dcc309c062 100644 (file)
@@ -950,7 +950,8 @@ void            gtk_requisition_free     (GtkRequisition       *requisition);
 GdkEventExpose *  _gtk_cairo_get_event                    (cairo_t      *cr);
 
 void              _gtk_widget_draw_internal               (GtkWidget    *widget,
-                                                           cairo_t      *cr);
+                                                           cairo_t      *cr,
+                                                           gboolean      clip_to_size);
 void              _gtk_widget_set_has_default             (GtkWidget    *widget,
                                                            gboolean      has_default);
 void              _gtk_widget_set_has_grab                (GtkWidget    *widget,